package cmpFunction;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.CRC32;

import org.apache.commons.io.FileUtils;

import com.alibaba.fastjson.JSONArray;

import dbConn.DBconn;

/**
 *
 * 1.有A和B两个目录，目录所在位置及层级均不确定
 * 2.需要以B为基准找出两个目录中所有有改动的文件（文件或内容增加、修改、删除），将有改动的文件放入第三个目录中，层级结构与原目录相同
 * 3.将所有新增与更新信息记录到更新日志文件中
 * 4.将删除信息单独记录到删除日志文件中
 * 5.每次执行diff工具需要生成一个新的以日期命名的目录存放文件
 */

public class cmpFunc {
	
	

    public static void scanFileDirectory(String sourceFileUrl, String currentFileUrl, String diffFileUrl) 
    {
        // 1. 在diffUrl目录下，创建日期格式的文件夹，用于存放改动的文件
        // 1.1 获取当前日期
        String nowTime = createCurrentTime();
        // 1.2创建日期形式的文件目录
        File fileDire = new File(diffFileUrl, nowTime);
        fileDire.mkdirs();
        String diffFilePath = fileDire.getAbsolutePath();
        // 2,遍历出删除的信息，并记录到删除日志文件中
        // 2.1创建删除日志文件
        String rootPath = fileDire.getAbsolutePath();
        File deleteLogFile = new File(rootPath, "delete.log");
        try {
            deleteLogFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        } 
        // 2.2遍历出删除的信息
        HashMap<String, Long> sourceUrlMap = getAllFileMap(sourceFileUrl);
        HashMap<String, Long> currentUrlMap = getAllFileMap(currentFileUrl);
        List<String> deleteFiles = new ArrayList<String>();
        String deleteCurrentTime = createCurrentTime();
        String diffMessage = "-------- Diff时间：" + deleteCurrentTime + " --------";
        try
        {
            FileUtils.writeStringToFile(deleteLogFile, diffMessage + "\n", "UTF-8", true);
        } 
        catch (IOException e1) 
        {
            e1.printStackTrace();
        }
        long start = System.currentTimeMillis();
        int delFilecount = 0;
        for (Map.Entry<String, Long> sourceEntry : sourceUrlMap.entrySet()) {
            // 遍历原版本目录下的文件，如果该文件不在当前版本目录下面，即该文件被删除了
            if (!currentUrlMap.containsKey(sourceEntry.getKey())) {
                deleteFiles.add(sourceEntry.getKey());
                delFilecount++;
            }
        }
        long end = System.currentTimeMillis();
        // 2.3 删除的信息记录到删除日志文件中
        String fileCount = "-------- 共删除文件" + delFilecount + "个--------";
        String endContent = "-------- 运行完毕，耗时：" + (end - start) + "ms";
        try {
            FileUtils.writeLines(deleteLogFile, "UTF-8", deleteFiles, true);
            FileUtils.write(deleteLogFile, fileCount + "\n", "UTF-8", true);
            FileUtils.write(deleteLogFile, endContent + "\n", "UTF-8", true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3.将所有新增与更新信息记录到更新日志文件中
        // 3.1 创建新增/更新日志文件
        File updateAndAddLogFile = new File(rootPath, "updateAndAdd.log");
        try {
            updateAndAddLogFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 3.2遍历新增与更新记录,并存入到集合中
        List<String> addFiles = new ArrayList<String>();
        List<String> updateFiles = new ArrayList<String>();
        /**
         * addOrUpdateFileUrls的key-value分别为currentFileUrl文件的全路径名、
         * diffFileUrl文件的全路径名 通过文件的完全路径可以获得文件对象，用于后面的文件复制操作
         */
        Map<String, String> addOrUpdateFileUrls = new HashMap<String, String>();
        int addCount = 0;
        int updateCount = 0;
    	JSONArray arraylist=new JSONArray();
        long fileAddOrUpdatestart = System.currentTimeMillis();
        for (Map.Entry<String, Long> currentUrlMapEntry : currentUrlMap.entrySet()) {
            String currentUrlSuffix = currentUrlMapEntry.getKey();
            // 如果元素存在原来的目录下，并且crc相同，就是更新操作
            if (sourceUrlMap.containsKey(currentUrlMapEntry.getKey())) {
                try {
                    long sourceUrlCrc = sourceUrlMap.get(currentUrlMapEntry.getKey());
                    long currentUrlCrc = currentUrlMapEntry.getValue();
                    if (currentUrlCrc != sourceUrlCrc) {
                        updateCount++;
                        updateFiles.add(currentUrlSuffix);
                        addOrUpdateFileUrls.put(currentFileUrl + currentUrlSuffix, diffFilePath + currentUrlSuffix);
                        //如果文件属于更新这比较文件的差异话并且把差异内容存入json arraylist
                        System.out.printf("#### currentFileUrl == %s  sourceFileUrl == %s\n",(sourceFileUrl +currentUrlSuffix).toString(),(currentFileUrl+currentUrlSuffix).toString());
                        cmpFuncOther diffFile=new cmpFuncOther();
                        diffFile.doDiff((sourceFileUrl +currentUrlSuffix).toString(), (currentFileUrl+currentUrlSuffix).toString(),arraylist);
                        arraylist.toString();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } else {// 如果元素不存在A目录下，就是新增的元素
                addCount++;
                addFiles.add(currentUrlSuffix);
                addOrUpdateFileUrls.put(currentFileUrl + currentUrlSuffix, diffFilePath + currentUrlSuffix);
            }
        }
        //打印json array list数据并插入远端服务器数据库
        System.out.printf("%s\n", arraylist.toString());
 
        java.util.Iterator<Object> it = arraylist.iterator();
        DBconn.setFuncInfo(it);
		
  
        long fileAddOrUpdateend = System.currentTimeMillis();
        String fileAddOrUpdate = "-------- 运行完毕，耗时：" + (fileAddOrUpdateend - fileAddOrUpdatestart) + "ms";
        // 3.3写入日志文件
        String addAndUpdateCurrentTime = createCurrentTime();
        String addAndUpdateDiffMessage = "-------- Diff时间：" + addAndUpdateCurrentTime + " --------";
        String updateCountMessage = "-------- 共更新文件" + updateCount + "个 -------";
        String addCountMessage = "-------- 共新增文件" + addCount + "个 -------";
        try {
            FileUtils.writeStringToFile(updateAndAddLogFile, addAndUpdateDiffMessage + "\n", "UTF-8", true);
            FileUtils.writeStringToFile(updateAndAddLogFile, updateCountMessage + "\n", "UTF-8", true);
            FileUtils.writeLines(updateAndAddLogFile, "UTF-8", updateFiles, true);
            FileUtils.writeStringToFile(updateAndAddLogFile, addCountMessage + "\n", "UTF-8", true);
            FileUtils.writeLines(updateAndAddLogFile, "UTF-8", addFiles, true);
            FileUtils.writeStringToFile(updateAndAddLogFile, fileAddOrUpdate + "\n", "UTF-8", true);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 4.将有新增/修改的文件放入第三个目录中
        filesCopy(addOrUpdateFileUrls);
    }

    /**
     * 循环遍历Map 将路径key获得的文件 复制到value全路径下
     */
    private static boolean  filesCopy(Map<String, String> addOrUpdateFileUrls){
        for (Map.Entry<String, String> addOrUpdateEntry : addOrUpdateFileUrls.entrySet()) {
            String filePath = addOrUpdateEntry.getValue();
            File diffFile = new File(addOrUpdateEntry.getValue());
            String fileDirs = filePath.replace(diffFile.getName(), "");
            File creFileDir = new File(fileDirs);
            creFileDir.mkdirs();
            FileChannel inputChannel = null;
            FileChannel outputChannel = null;
            FileInputStream fileInputStream = null;
            FileOutputStream fileOutputStream = null;
            try {
                fileInputStream = new FileInputStream(new File(addOrUpdateEntry.getKey()));
                inputChannel = fileInputStream.getChannel();
                fileOutputStream = new FileOutputStream(diffFile);
                outputChannel = fileOutputStream.getChannel();
                outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    inputChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    outputChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }
    /**
     * 获取yyyy年MM月dd日HH点mm分ss秒格式的当前时间
     *
     * @return
     */
    private static String createCurrentTime() {
        Date now = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日HH点mm分ss秒");
        String nowTime = dateFormat.format(now);
        return nowTime;
    }

    /**
     * 将获取到的文件存到map中
     *
     * @param path
     * @return
     */
    private static HashMap<String, Long> getAllFileMap(String DirectoryUrl) {

        List<File> allFileList = new ArrayList<File>();
        HashMap<String, Long> resMap = new HashMap<String, Long>();

        allFileList = getAllFile(new File(DirectoryUrl), allFileList);
        for (File file : allFileList) {
            resMap.put(file.getAbsolutePath().replace(DirectoryUrl, ""), getFileCRC(file));
        }
        return resMap;
    }

    /**
     * 递归遍历所有文件
     *
     * @param file
     * @param allFileList
     * @return
     */
    private static List<File> getAllFile(File file, List<File> allFileList) {
        if (file.exists()) {
            if (file.isDirectory()) {
                File f[] = file.listFiles();
                for (File tempFile : f) {
                    getAllFile(tempFile, allFileList);
                }
            } else {
                allFileList.add(file);
            }
        }
        return allFileList;
    }

    /**
     * 获取文件的CRC
     *
     * @param file
     * @return
     * @throws IOException
     */
    private static long getFileCRC(File file) {
        BufferedInputStream bsrc = null;
        CRC32 crc = new CRC32();
        try {
            bsrc = new BufferedInputStream(new FileInputStream(file));
            byte[] bytes = new byte[1024];
            int i;
            while ((i = bsrc.read(bytes)) != -1) {
                crc.update(bytes, 0, i);
            }
        } catch (Exception e) {

        } finally {
            if (bsrc != null) {
                try {
                    bsrc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return crc.getValue();
    }
}
